﻿using System;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace WindowsGame.GameObject
{
	/// <summary>
	/// SpaceShip is the only game object.
	/// </summary>
	public class SpaceShip
	{
		private Model spaceShipModel;
		private Matrix[] transforms;

		public SpaceShip() : this(Vector3.Zero)
		{
		}

		public SpaceShip(Vector3 modelPosition)
		{
			ModelRotation = 0.0f;
			ModelPosition = modelPosition;
			ModelVelocity = Vector3.Zero;
		}

		// Load model and set view/projection matrices.
		public void LoadContent(Model theSpaceShipModel, Matrix viewMatrix, Matrix projectionMatrix)
		{
			spaceShipModel = theSpaceShipModel;
			transforms = new Matrix[spaceShipModel.Bones.Count];
			spaceShipModel.CopyAbsoluteBoneTransformsTo(transforms);

			foreach (BasicEffect effect in spaceShipModel.Meshes.SelectMany(mesh => mesh.Effects.Cast<BasicEffect>()))
			{
				effect.EnableDefaultLighting();
				effect.View = viewMatrix;
				effect.Projection = projectionMatrix;
			}
		}

		// Update rotate, move and warp if actions are invoked.
		public void Update(Single rotate, Single move, Boolean warp)
		{
			// Rotate.
			if (rotate != 0)
			{
				const Single scale = 0.10f;
				ModelRotation -= rotate * scale;
			}

			// Move.
			if (move != 0)
			{
				// Create some velocity if move action invoked.
				Vector3 modelVelocityAdd = Vector3.Zero;

				// Find out thrust direction using rotation.
				Single sin = -(Single)Math.Sin(ModelRotation);
				Single cos = -(Single)Math.Cos(ModelRotation);

				modelVelocityAdd.X = sin;
				modelVelocityAdd.Z = cos;

				// Scale direction by the amount of movement.
				modelVelocityAdd *= move;

				// Finally, add this vector to our velocity.
				ModelVelocity += modelVelocityAdd;
			}

			// Warp.
			if (warp)
			{
				ModelPosition = Vector3.Zero;
				ModelVelocity = Vector3.Zero;
				ModelRotation = 0.0f;
			}

			// Add velocity to position and bleed off velocity over time.
			ModelPosition += ModelVelocity;
			ModelVelocity *= 0.97f;
		}

		// Draw model.
		public void Draw()
		{
			foreach (ModelMesh mesh in spaceShipModel.Meshes)
			{
				foreach (BasicEffect effect in mesh.Effects)
				{
					effect.World = transforms[mesh.ParentBone.Index]
						* Matrix.CreateRotationY(ModelRotation)
						* Matrix.CreateTranslation(ModelPosition);
				}

				mesh.Draw();
			}
		}

		public Single ModelRotation { get; private set; }
		public virtual Vector3 ModelPosition { get; private set; }
		public Vector3 ModelVelocity { get; private set; }
	}
}